package com.zhouzhou.fastjava.query;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.zhouzhou.fastjava.query.dialect.Dialect;
import freemarker.template.Configuration;
import com.zhouzhou.fastjava.query.converter.IntegerToBooleanConvert;
import com.zhouzhou.fastjava.query.executors.JdbcTemplateQueryExecutor;
import com.zhouzhou.fastjava.query.executors.LessSubQueryJdbcTemplateExecutor;
import org.springframework.core.convert.support.DefaultConversionService;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.Map;
import java.util.Set;

public class QueryConfiguration {

    private Configuration freemarkerConfiguration = new Configuration(Configuration.VERSION_2_3_23);

    private final JSONConfigBuilder configBuilder;

    private boolean debug = false;

    private boolean showSql = true;

    private DataSource dataSource;

    private ColumnMapping columnMapping = DefaultColumnMapping.getInstance();

    private final Map<String, QuerySetting> querySettings = Maps.newHashMap();

    private final Map<String, LabelSetting> labelSettings = Maps.newHashMap();

    private final Map<String, QueryField> wildcardKeyQueryFields = Maps.newHashMap();

    private final Map<String, String> sqls = Maps.newHashMap();

    private final DefaultConversionService conversionService = new DefaultConversionService();

    private boolean forceCaseIgnore = true;

    private Dialect dialect;

    public QueryConfiguration(JSONConfigBuilder configBuilder) {
        this.configBuilder = configBuilder;
        registerConverters();
        freemarkerConfiguration.setDefaultEncoding("utf-8");
    }

    public QueryExecutor newExecutor() {
        return new JdbcTemplateQueryExecutor(this);
    }

    public QueryExecutor newLessSubQueryExcutor() {
        return new LessSubQueryJdbcTemplateExecutor(this);
    }

    public Configuration getFreemarkerConfiguration() {
        return freemarkerConfiguration;
    }

    public DataSource getDataSource() {
        return dataSource;
    }

    public boolean isShowSql() {
        return showSql;
    }

    public ModuleQueryStatement getModuleQueryStatement(String module) {
        QuerySetting querySetting = this.querySettings.get(module);
        if (querySetting == null) {
            querySetting = new QuerySetting();
        }
        LabelSetting labelSetting = this.labelSettings.get(module);
        if (labelSetting == null) {
            labelSetting = new LabelSetting();
        }
        return new ModuleQueryStatement(querySetting, labelSetting, this.sqls.get(module));
    }

    public void reloadModule(String module) throws IOException {
        configBuilder.reloadModule(module);
    }

    public void registerConverters() {
        conversionService.addConverter(new IntegerToBooleanConvert());
    }

    public boolean isDebug() {
        return debug;
    }

    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    public void setShowSql(boolean showSql) {
        this.showSql = showSql;
    }

    public boolean isForceCaseIgnore() {
        return forceCaseIgnore;
    }

    public void setForceCaseIgnore(boolean forceCaseIgnore) {
        this.forceCaseIgnore = forceCaseIgnore;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public DefaultConversionService getConversionService() {
        return conversionService;
    }

    public Map<String, QuerySetting> getQuerySettings() {
        return querySettings;
    }

    public Map<String, LabelSetting> getLabelSettings() {
        return labelSettings;
    }

    public Map<String, String> getSqls() {
        return sqls;
    }

    public Set<String> getModules() {
        return Sets.newTreeSet(getSqls().keySet());
    }

    public ColumnMapping getColumnMapping() {
        return columnMapping;
    }

    public void setColumnMapping(ColumnMapping columnMapping) {
        this.columnMapping = columnMapping;
    }

    public Map<String, QueryField> getWildcardKeyQueryFields() {
        return wildcardKeyQueryFields;
    }

    public void addWildcardKeyQueryField(String pattern, QueryField queryField) {
        this.wildcardKeyQueryFields.put(pattern, queryField);
    }

    public void setDialect(Dialect dialect) {
        this.dialect = dialect;
    }

    public Dialect getDialect() {
        return dialect;
    }

}
